package com.core.mvc.service;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.core.IFilter;
import com.core.mvc.Require;
import com.core.mvc.annotation.Action;
import com.core.mvc.annotation.RequireFilter;
import com.core.mvc.annotation.Service;
import com.core.mvc.config.InitConfig;
import com.core.utils.ClassFilter;
import com.core.utils.ClassUtils;

/**
 * 服务解析器
 * 
 * @author 殷田
 *
 */
class ServiceLoader
{
	private static ServiceLoader loader;

	private ServiceLoader()
	{

	}

	public static ServiceLoader getLoader()
	{
		if ( loader == null )
		{
			synchronized ( ServiceLoader.class )
			{
				if ( loader == null )
				{
					loader = new ServiceLoader();
				}
			}
		}
		return loader;
	}

	public Map< String, ServiceBean > load( InitConfig init )
	{
		Map< String, ServiceBean > services = new HashMap< String, ServiceBean >();
		scanPackage( init.getScanPaths(), services );
		return services;
	}

	/**
	 * 扫描配置类 注解中的信息
	 *
	 * @param configClassName配置类的名称
	 */
	private void scanPackage( List< String > scanPaths, final Map< String, ServiceBean > services )
	{
		try
		{
			for ( String packageName : scanPaths )
			{
				ClassUtils.getClasses( packageName, null, new ClassFilter()
				{
					@Override
					public boolean accept( Class< ? > aClass )
					{
						loadServiceBean( aClass, services );
						return false;
					}
				} );
			}
		}
		catch ( Exception e )
		{
			e.printStackTrace();
		}
	}

	/**
	 * 填充服务信息
	 * 
	 * @param clazz
	 * @return
	 */
	private void loadServiceBean( Class< ? > clazz, Map< String, ServiceBean > services )
	{
		try
		{
			if ( clazz.isAnnotationPresent( Service.class ) )
			{
				Service action = clazz.getAnnotation( Service.class );
				String name = action.value();
				if ( name != null && name.length() > 0 )
				{
					ServiceBean ret = new ServiceBean();
					ret.setTarget( clazz.newInstance() );
					// 装在过滤器
					if ( clazz.isAnnotationPresent( RequireFilter.class ) )
					{
						RequireFilter requireFilter = clazz.getAnnotation( RequireFilter.class );
						Class< ? extends IFilter< Require > >[] filters = requireFilter.value();
						if ( filters != null && filters.length > 0 )
						{
							IFilterHandler< Require > filterHandler = new IFilterHandler< Require >();
							for ( int i = 0; i < filters.length; i++ )
							{
								filterHandler.addFilter( filters[i].newInstance() );
							}
							ret.setFilterHandler( filterHandler );
						}
					}
					loadActionBean( clazz, ret );
					services.put( name, ret );
				}
			}
		}
		catch ( Exception e )
		{
			e.printStackTrace();
		}
	}

	private void loadActionBean( Class< ? > clazz, ServiceBean serviceBean )
	{
		try
		{
			Method[] methods = clazz.getMethods();
			if ( methods != null && methods.length > 0 )
			{
				for ( int i = 0; i < methods.length; i++ )
				{
					Method method = methods[i];
					if ( method.isAnnotationPresent( Action.class ) )
					{
						Action action = method.getAnnotation( Action.class );
						String name = action.value();
						if ( name != null && name.length() > 0 )
						{
							Class< ? >[] params = method.getParameterTypes();
							if ( params.length == 1 && params[0].equals( Require.class ) )
							{
								ActionBean actionBean = new ActionBean();
								actionBean.setMethod( method );
								// 装在过滤器
								if ( method.isAnnotationPresent( RequireFilter.class ) )
								{
									RequireFilter requireFilter = method
													.getAnnotation( RequireFilter.class );
									Class< ? extends IFilter< Require > >[] filters = requireFilter
													.value();
									if ( filters != null && filters.length > 0 )
									{
										IFilterHandler< Require > filterHandler = new IFilterHandler< Require >();
										for ( int j = 0; j < filters.length; j++ )
										{
											filterHandler.addFilter( filters[j].newInstance() );
										}
										actionBean.setFilterHandler( filterHandler );
									}
								}
								serviceBean.putAction( name, actionBean );
							}
						}
					}
				}
			}
		}
		catch ( Exception e )
		{
			e.printStackTrace();
		}
	}
}
